#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "sdkconfig.h"
#include "esp_flash.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "spi_flash_mmap.h"
#include <string.h>
#include "reg.h"
#include "nvs_app.h"

#define NVS_NAMESPACE "list"

extern uint16_t ver_deg;
extern uint16_t rs485_baud;
extern char spp_name[16];

// 队列
static QueueHandle_t nvs_send_queue;

// void nvs_write_param(void)
// {
//     nvs_handle_t nvs_handle;
//     //1、打开namespace
//     esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
//     if (err != ESP_OK)
//     {
//         return;
//     }
//     //2、写入namespace信息
//     err = nvs_set_u16(nvs_handle, "rs485_baud", rs485_baud);
//     if (err == ESP_OK)
//     {
//         ESP_LOGE("nvs", "write rs485_baud: %d", rs485_baud);
//     }
//     err = nvs_set_str(nvs_handle, "spp_name", spp_name);
//     if (err == ESP_OK)
//     {
//         ESP_LOGE("nvs", "write spp_name: %s", spp_name);
//     }
//     //3、提交namespace
//     err = nvs_commit(nvs_handle);
//     if (err == ESP_OK)
//     {
//         ESP_LOGE("nvs", "commit success");
//     }
//     else
//     {
//         ESP_LOGE("nvs", "commit fail,err is %d", err);
//     }
//     //3、关闭namespace
//     nvs_close(nvs_handle);
// }

int nvs_namespace_check(const char* namespace_name)
{
    nvs_handle_t nvs_handle;
    //1、打开namespace
    esp_err_t err = nvs_open(namespace_name, NVS_READONLY, &nvs_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE("nvs", "nvs open fail,err is %d", err);
        return -1;
    }
    //2、读取namespace信息
    uint16_t rs485_baud_tmp;
    err = nvs_get_u16(nvs_handle, "rs485_baud", &rs485_baud_tmp);
    if (err == ESP_OK)
    {
        rs485_baud = rs485_baud_tmp;
        ESP_LOGE("nvs", "rs485_baud: %d", rs485_baud);
    }
    else
    {
        ESP_LOGE("nvs", "get rs485_baud fail,err is %d", err);
    }
    char spp_name_tmp[16] = {0};
    size_t spp_name_len = sizeof(spp_name_tmp);
    err = nvs_get_blob(nvs_handle, "spp_name", spp_name_tmp, &spp_name_len);
    if (err == ESP_OK)
    {
        if(spp_name_len == sizeof(spp_name_tmp))
        {
            memcpy(spp_name, spp_name_tmp, spp_name_len);
            ESP_LOGE("nvs", "spp_name: %s", spp_name_tmp);
        }
        else
        {
            ESP_LOGE("nvs", "spp_name_len is %d,not equal to %d", spp_name_len, sizeof(spp_name_tmp));
        }
    }
    else
    {
        ESP_LOGE("nvs", "get spp_name fail,err is %d", err);
    }
    //3、关闭namespace
    nvs_close(nvs_handle);
    return 0;
}

static int nvs_write_param_cmd(NVS_OBJ para_index)
{
    nvs_handle_t nvs_handle;
    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE("nvs", "nvs open fail,err is %d", err);
        return -1;
    }
    switch(para_index)
    {
        case NVS_BAUD:
        {
            err = nvs_set_u16(nvs_handle, "rs485_baud", rs485_baud);
            if (err == ESP_OK)
            {
                ESP_LOGE("nvs", "write rs485_baud: %d", rs485_baud);
            }
        }
        break;
        case NVS_SPP_NAME:
        {
            err = nvs_set_blob(nvs_handle, "spp_name", spp_name, sizeof(spp_name));
            if (err == ESP_OK)
            {
                ESP_LOGE("nvs", "write spp_name: %s", spp_name);
            }
        }
        break;
        default:
        {
            
        }
        break;
    }
    err = nvs_commit(nvs_handle);
    if (err == ESP_OK)
    {
        ESP_LOGE("nvs", "commit success");
    }
    else
    {
        ESP_LOGE("nvs", "commit fail,err is %d", err);
    }
    nvs_close(nvs_handle);
    return 0;
}

int nvs_write_send(NVS_OBJ cmd)
{
    uint8_t cmd_tmp = (uint8_t)cmd;
    if(nvs_send_queue != NULL)
    {
        if(xQueueSend(nvs_send_queue, &cmd_tmp, 1000 / portTICK_PERIOD_MS) == pdTRUE)
        {
            ESP_LOGE("nvs", "nvs_send_queue send success");
        }
        else
        {
            ESP_LOGE("nvs", "nvs_send_queue send fail");
        }
    }
    else
    {
        ESP_LOGE("nvs", "nvs_send_queue is NULL");
    }
    return 0;
}

static void nvs_write_task(void *arg)
{
    nvs_send_queue = xQueueCreate(10, sizeof(uint8_t));
    if(nvs_send_queue == NULL)
    {
        ESP_LOGE("nvs", "nvs_send_queue create fail");
        return;
    }
    while (1)
    {
        uint8_t cmd = 0;
        if (xQueueReceive(nvs_send_queue, &cmd, portMAX_DELAY) == pdTRUE)
        {
            if(cmd != 0)
            {
                nvs_write_param_cmd((NVS_OBJ)cmd);
            }
        }
        //增加延时，降低CPU占用
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    vQueueDelete(nvs_send_queue);
    nvs_send_queue = NULL;
    vTaskDelete(NULL);
}

void nvs_app_main(void)
{
    //初始化NVS
    esp_err_t ret = nvs_flash_init();
    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) 
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }
    //打印上电保存信息
    ret = nvs_namespace_check(NVS_NAMESPACE);
    if(ret == -1)
    {
        ESP_LOGE("nvs", "fault nvs namespace");
    }
    //初始化Hold寄存器

    //创建一个任务
    xTaskCreate(nvs_write_task, "nvs_write_task", 4096, NULL, 1, NULL);
}